﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Web;
using System.Data;
using System.Linq;
using Charts = System.Web.UI.DataVisualization.Charting;
using System.Drawing;
using System.Web.UI.WebControls;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Web.UI.HtmlControls;

using OCXS;
using OCXS.OCXSServiceLibrary;
using OCXS.OCXSServiceLibrary.Administration;

namespace OCXS.OCXSAdministration {

    /// <summary>
    /// Page for showing variables and administration panel.
    /// </summary>
	public partial class _Default : System.Web.UI.Page {

        protected const int ChartBufferSize = 10;

        #region Loading

        /// <summary>
        /// Loading procedure
        /// </summary>
		protected void Page_Load(object sender, EventArgs e) {

            if (!this.IsPostBack) {
                // Fisrt time

                // Saving state
                this.ViewState["VariablesDataStore"] = new Dictionary<String, VariableRepresentation>();
                this.ViewState["SubscriptionsDataStore"] = new Dictionary<String, SubscriptionRepresentation>();

            } else {
                // Other times here



            }
           
		}

        #endregion

        #region Event handlers

        /// <summary>
        /// Create charts.
        /// </summary>
        protected void Variables_GridView_RowDataBound(object sender, GridViewRowEventArgs e) {
            if (e.Row.RowType == DataControlRowType.DataRow) {
                Charts.Chart chart = new Charts.Chart();
                this.FormatChart(ref chart);
                this.PopulateChart(ref chart, e.Row.DataItem);
                e.Row.Cells[1].Controls.Add(chart);

                //
                HtmlGenericControl mainDiv = new HtmlGenericControl("div");
                mainDiv.Style.Add("width", "auto");
                mainDiv.Style.Add("padding", "5px 5px 5px 5px");
                mainDiv.Style.Add("cursor", "default");
                
                // Onmouseover event
                mainDiv.Attributes.Add("onmouseover", "ShowTooltip('variable_tooltip', '" +
                    ((VariableRepresentation)e.Row.DataItem).VariableName + "', '" +
                    ((VariableRepresentation)e.Row.DataItem).VariableType + "', '" +
                    ((VariableRepresentation)e.Row.DataItem).VariableDescription +"')");
                
                mainDiv.Attributes.Add("onmouseout", "HideTooltip('variable_tooltip')");
                mainDiv.InnerHtml = "<span>" + ((VariableRepresentation)e.Row.DataItem).VariableName + "</span>";
                e.Row.Cells[0].Controls.Add(mainDiv);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected void Subscriptions_Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e) {

            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {

                // Fill SID
                ((Literal)e.Item.FindControl("SID_Literal")).Text = ((SubscriptionRepresentation)e.Item.DataItem).SID +
                    ((((SubscriptionRepresentation)e.Item.DataItem).Disposed) ? " [disposed]" : "");

                foreach (string varid in ((SubscriptionRepresentation)e.Item.DataItem).VariableIds) {

                    ((HtmlGenericControl)(e.Item.FindControl("VariablesList_Div"))).InnerHtml += 
                        "<span class='subscriptionvarid'>" + varid + "</span>";
                
                }

            }

        }

        /// <summary>
        /// 
        /// </summary>
        protected void Variables_Timer_Tick(object sender, EventArgs e) {
            string errs = null;
            this.ManageVariablesUpdate(out errs);

            this.Variables_GridView.DataSource = 
                ((Dictionary<String, VariableRepresentation>)this.ViewState["VariablesDataStore"]).Values.ToArray<VariableRepresentation>();
            this.Variables_GridView.DataBind();

        }

        /// <summary>
        /// 
        /// </summary>
        protected void Subscriptions_Timer_Tick(object sender, EventArgs e) {
            string errs = null;
            this.ManageSubscriptionsUpdate(out errs);

            this.Subscriptions_Repeater.DataSource =
                ((Dictionary<String, SubscriptionRepresentation>)
                    this.ViewState["SubscriptionsDataStore"]).Values.ToArray<SubscriptionRepresentation>();

            this.Subscriptions_Repeater.DataBind();
        }

        /// <summary>
        /// 
        /// </summary>
        protected void ServerStatus_Timer_Tick(object sender, EventArgs e) {
            string errs = null;
            this.ManageServerStatusUpdate(out errs);
        }

        #endregion

        #region Helper functions

        /// <summary>
        /// Formats the chart.
        /// </summary>
        /// <param name="c">Chart to format.</param>
        private void FormatChart(ref Charts.Chart chart) {
            chart.Width = 250;
            chart.Height = 50;
        }

        /// <summary>
        /// Populates the chart.
        /// </summary>
        /// <param name="c">Chart to format.</param>
        private void PopulateChart(ref Charts.Chart chart, object dataitem) {
            VariableRepresentation vr = (VariableRepresentation)dataitem;
            Charts.Series s = new Charts.Series("Variable");
            // Style
            chart.BackColor = ColorTranslator.FromHtml("#f9f9ed");
            chart.BorderlineColor = ColorTranslator.FromHtml("#f9f9ed");
            chart.BorderlineDashStyle = Charts.ChartDashStyle.Solid;
            // Axis
            s.XAxisType = Charts.AxisType.Primary;
            s.YAxisType = Charts.AxisType.Primary;
            s.XValueType = Charts.ChartValueType.Int32;
            s.YValueType = Charts.ChartValueType.Int32;
            // Chart type
            s.ChartType = Charts.SeriesChartType.Line;
            // Values
            for (int i = 0; i < vr.VariableValues.Length; i++)
                s.Points.Add(new Charts.DataPoint(i, vr.VariableValues[i]));
            // Chart area
            Charts.ChartArea a = new Charts.ChartArea("MainChartArea");
            a.BorderColor = Color.FromArgb(0, 255, 255, 255);
            a.BorderDashStyle = Charts.ChartDashStyle.Solid;
            a.BackColor = Color.FromArgb(0, 255, 255, 255);
            a.AxisY.LineColor = Color.FromArgb(64, 64, 64, 64);
            a.AxisY.LabelStyle.Font = new Font("Trebuchet MS", 2.25f, FontStyle.Regular, GraphicsUnit.Point);
            a.AxisX.Enabled = Charts.AxisEnabled.False;
            a.AxisX.IsMarginVisible = false;
            a.AxisX.IsLogarithmic = false;
            a.AxisX.IsStartedFromZero = false;
            a.AxisX.IntervalAutoMode = Charts.IntervalAutoMode.VariableCount;
            a.AxisX.MajorGrid.IntervalType = Charts.DateTimeIntervalType.Auto;
            a.AxisX.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
            a.AxisX.MajorGrid.LineDashStyle = Charts.ChartDashStyle.Solid;
            a.AxisY.IsMarginVisible = false;
            a.AxisY.IsLogarithmic = false;
            a.AxisY.IsStartedFromZero = true;
            a.AxisY.IntervalAutoMode = Charts.IntervalAutoMode.VariableCount;
            a.AxisY.MajorGrid.IntervalType = Charts.DateTimeIntervalType.Auto;
            a.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 64);
            a.AxisY.MajorGrid.LineDashStyle = Charts.ChartDashStyle.Solid;
            // Assigning
            chart.ChartAreas.Add(a);
            chart.Series.Add(s);
        }

        /// <summary>
        /// Used only to manage the dictionary update.
        /// </summary>
        /// <param name="errors">Returns possible errors.</param>
        private void ManageVariablesUpdate(out string errors) {

            IOCXSService SVC = null;

            // Communication
            try {

                ServiceEndpoint httpEndpoint =
                    new ServiceEndpoint(ContractDescription.GetContract(typeof(IOCXSService)),
                        new BasicHttpBinding(), new EndpointAddress("http://localhost:82/OCXS/OCXS.svc"));
                ChannelFactory<IOCXSService> MyServiceChannelFactory =
                    new ChannelFactory<IOCXSService>(httpEndpoint);
                SVC = MyServiceChannelFactory.CreateChannel();

            } catch (Exception e) {
                errors = "Communication error: " + e.Message;
            }

            // Processing
            try {
                
                UpdateVariablesResponse res = SVC.UpdateVariables(new UpdateVariablesRequest());

                if (this.ViewState["VariablesDataStore"] == null) {
                    errors = "No datastore";
                    return;
                }

                // Retieving datastore
                Dictionary<String, VariableRepresentation> datastore =
                    (Dictionary<String, VariableRepresentation>)this.ViewState["VariablesDataStore"];

                // Browsing variables
                for (int i = 0; i < res.VariableNames.Length; i++ ) {

                    VariableRepresentation vr = null;
                    if (((Dictionary<String, VariableRepresentation>)this.ViewState["VariablesDataStore"]).TryGetValue(
                        res.VariableNames[i], out vr)) {

                        // Key match --> Element is here
                        vr.AddValue(res.VariableValues[i]);


                    } else {

                        // No key matches --> New element
                        VariableRepresentation newvr = new VariableRepresentation(
                                res.VariableNames[i], 
                                res.VariableTypes[i], 
                                res.VariableDescriptions[i], 
                                ChartBufferSize);

                        newvr.AddValue(res.VariableValues[i]);
                        datastore.Add(res.VariableNames[i], newvr);


                    }

                }

                errors = null;

            } catch (Exception e) {
                errors = "Processing error: " + e.Message;
            }
        }

        /// <summary>
        /// 
        /// 
        /// </summary>
        /// <param name="errors">Returns possible errors.</param>
        private void ManageSubscriptionsUpdate(out string errors) {

            IOCXSService SVC = null;

            // Communication
            try {

                ServiceEndpoint httpEndpoint =
                    new ServiceEndpoint(ContractDescription.GetContract(typeof(IOCXSService)),
                        new BasicHttpBinding(), new EndpointAddress("http://localhost:82/OCXS/OCXS.svc"));
                ChannelFactory<IOCXSService> MyServiceChannelFactory =
                    new ChannelFactory<IOCXSService>(httpEndpoint);
                SVC = MyServiceChannelFactory.CreateChannel();

            }
            catch (Exception e) {
                errors = "Communication error: " + e.Message;
            }

            // Processing
            try {

                UpdateSubscriptionsResponse res = SVC.UpdateSubscriptions(new UpdateSubscriptionRequest());

                if (this.ViewState["SubscriptionsDataStore"] == null) {
                    errors = "No datastore";
                    return;
                }

                // Retieving datastore
                Dictionary<String, SubscriptionRepresentation> datastore =
                    (Dictionary<String, SubscriptionRepresentation>)this.ViewState["SubscriptionsDataStore"];

                // Creating Set for double checking missing elements
                HashSet<string> checkSIDs = new HashSet<string>();
                foreach (string sid in datastore.Keys)
                    checkSIDs.Add(sid);
                
                // Browsing subscriptions
                for (int i = 0; i < res.SIDs.Length; i++) {

                    SubscriptionRepresentation sr = null;
                    if (datastore.TryGetValue(res.SIDs[i], out sr)) {

                        // Key match --> Element is here
                        
                        sr = new SubscriptionRepresentation(res.SIDs[i], res.Disposed[i], res.VariableIDs[i]);
                        checkSIDs.Remove(res.SIDs[i]); /* Set double check removal */

                    } else {

                        // No key matches --> New element
                        SubscriptionRepresentation newsr = new SubscriptionRepresentation(res.SIDs[i], res.Disposed[i], res.VariableIDs[i]);
                        datastore.Add(res.SIDs[i], newsr);
                    }

                }

                // Deleting missing elements
                foreach (string sid in checkSIDs)
                    datastore.Remove(sid);

                errors = null;

            }
            catch (Exception e) {
                errors = "Processing error: " + e.Message;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="errors">Returns possible errors.</param>
        private void ManageServerStatusUpdate(out string errors) {

            IOCXSService SVC = null;

            // Communication
            try {

                ServiceEndpoint httpEndpoint =
                    new ServiceEndpoint(ContractDescription.GetContract(typeof(IOCXSService)),
                        new BasicHttpBinding(), new EndpointAddress("http://localhost:82/OCXS/OCXS.svc"));
                ChannelFactory<IOCXSService> MyServiceChannelFactory =
                    new ChannelFactory<IOCXSService>(httpEndpoint);
                SVC = MyServiceChannelFactory.CreateChannel();

            } catch (Exception e) {
                errors = "Communication error: " + e.Message;
            }

            // Processing
            try {

                UpdateServerStatusResponse res = SVC.UpdateServerStatus(new UpdateServerStatusRequest());

                this.SSGCCollNum_Literal.Text = res.GCCollectionNum.ToString();
                this.SSGCTotMem_Literal.Text = res.GCTotalMemory.ToString();
                this.SSGenTNum_Literal.Text = res.GeneratorThreadNum.ToString();
                this.SSSubNum_Literal.Text = res.SubscriptionNum.ToString();
                this.SSSubWTNum_Literal.Text = res.SubscriptionWatcherThreadNum.ToString();
                this.SSVarNum_Literal.Text = res.VariablesNum.ToString();

                errors = null;

            } catch (Exception e) {
                errors = "Processing error: " + e.Message;
            }
        }

        #endregion

    }

}
